package getWay

import (
	"encoding/json"
	"fmt"
	"gitee.com/manoshi/go-util/conf"
	"gitee.com/manoshi/go-util/const/GetWay"
	"gitee.com/manoshi/go-util/es"
	"gitee.com/manoshi/go-util/log"
	db "gitee.com/manoshi/go-util/mysqlrym"
	"gitee.com/manoshi/go-util/redis"
	"gitee.com/manoshi/go-util/util"
	"github.com/gin-gonic/gin"
	"net/http"
	"strings"
	"time"
)

type ServerResponse struct {
	Code    State  `json:"code"`          //0为成功，其他都是失败
	Msg     string `json:"msg,omitempty"` //非1000情况下的错误描述
	SubCode string `json:"subCode,omitempty"`
	SubMsg  string `json:"subMsg,omitempty"`
}

type ServerDataResponse struct {
	ServerResponse
	Data interface{} `json:"data,omitempty"`
}

func response(state State) ServerResponse {
	return ServerResponse{Code: state, Msg: state.String()}
}

func responseSub(state State, subCode, subMsg string) ServerResponse {
	return ServerResponse{Code: state, Msg: state.String(), SubCode: subCode, SubMsg: subMsg}
}

func FailGetWay(c *gin.Context, state State, subCode, subMsg string) {
	resp := responseSub(state, subCode, subMsg)
	log.Error(util.GetInterfaceToString(resp))
	c.JSON(http.StatusBadGateway, resp)
	c.Abort()
	LogEnd(c, resp)
}

func SuccessGetWay(c *gin.Context, state State, subCode, subMsg string) {
	resp := responseSub(state, subCode, subMsg)
	c.JSON(http.StatusOK, resp)
	c.Abort()
	LogEnd(c, resp)
}

func FailAndMsg(c *gin.Context, subCode, subMsg string) {
	db.Rollback()
	resp := ServerResponse{Code: BusinessError, Msg: "业务错误", SubCode: subCode, SubMsg: subMsg}
	log.Error(util.GetInterfaceToString(resp))
	c.JSON(http.StatusOK, resp)
	c.Abort()
	LogEnd(c, resp)
}

// FailAndMsgNoTx 不带事务
func FailAndMsgNoTx(c *gin.Context, subCode, subMsg string) {
	resp := ServerResponse{Code: BusinessError, Msg: "业务错误", SubCode: subCode, SubMsg: subMsg}
	log.Error(util.GetInterfaceToString(resp))
	c.JSON(http.StatusOK, resp)
	c.Abort()
	LogEnd(c, resp)
}

func SuccessNormal(c *gin.Context) {
	db.Commit()
	resp := response(OK)
	LogEnd(c, resp)
}

func SuccessDataNormal(c *gin.Context, data interface{}) {
	db.Commit()
	resp := ServerDataResponse{response(OK), data}
	LogEnd(c, resp)
}
func SuccessOtherData(c *gin.Context, data interface{}) {
	db.Commit()
	c.JSON(http.StatusOK, data)
	c.Abort()
	LogEnd(c, data)
}

// Success 有事务的用这个
func Success(c *gin.Context) {
	db.Commit()
	resp := response(OK)
	c.JSON(http.StatusOK, resp)
	c.Abort()
	LogEnd(c, resp)
}

// SuccessNoTx 不带事务提交
func SuccessNoTx(c *gin.Context) {
	resp := response(OK)
	c.JSON(http.StatusOK, resp)
	c.Abort()
	LogEnd(c, resp)
}

// SuccessData 有事务的用这个
func SuccessData(c *gin.Context, data interface{}) {
	db.Commit()
	resp := ServerDataResponse{response(OK), data}
	c.JSON(http.StatusOK, resp)
	c.Abort()
	LogEnd(c, resp)
}

// SuccessDataNoTx 不带事务提交
func SuccessDataNoTx(c *gin.Context, data interface{}) {
	resp := ServerDataResponse{response(OK), data}
	c.JSON(http.StatusOK, resp)
	c.Abort()
	LogEnd(c, resp)
}

func SuccessString(c *gin.Context, data string) {
	c.String(http.StatusOK, data)
	c.Abort()
	LogEnd(c, data)
}

func LogEnd(c *gin.Context, data interface{}) {
	esSwitch := redis.SwitchOpen(redis.ES日志开关 + conf.ServerName)
	startTime := GetStartTime(c)
	endTime := time.Now().UnixNano()
	var responseStr string
	if data != nil {
		dataJson, _ := json.Marshal(data)
		rs := string(dataJson)
		excludeUrl := []string{""}
		if esSwitch {
			if util.ArrayContains(excludeUrl, GetURL(c)) && len(rs) > conf.LogResponseLength {
				responseStr = rs[0:conf.LogResponseLength] + "......"
			} else {
				responseStr = rs
			}
		} else {
			if len(rs) > conf.LogResponseLength {
				responseStr = rs[0:conf.LogResponseLength] + "......"
			} else {
				responseStr = rs
			}
		}
	}
	token := GetToken(c)
	if esSwitch && checkLog(GetURL(c)) && checkLogType(c) && es.GetEsStatus() == 200 {
		esLog(c, responseStr)
		log.Info(fmt.Sprintf("结束,耗时%d毫秒 %s %s %s", (endTime-startTime)/1e6, GetMethod(c), GetURL(c), token))
	} else {
		if !c.GetBool(GetWay.UnLogResponse) {
			log.Info(fmt.Sprintf("返回数据：%s", responseStr))
		}
		log.Info(fmt.Sprintf("结束,耗时%d毫秒 %s %s %s %s %s", (endTime-startTime)/1e6, GetMethod(c), GetURL(c), token, GetClientIP(c), GetParams(c)))
	}

}

func esLog(c *gin.Context, response string) {
	currentUserId, _ := GetCurrentUserId(c)
	log := es.ServerLogModel{
		ServerName:   conf.ServerName,
		Env:          conf.Env,
		TimeStamp:    GetStartTime(c),
		ThreadNo:     fmt.Sprintf("%d", util.GetGID()),
		ServerIp:     GetServerIP(),
		ClientIp:     GetClientIP(c),
		Token:        GetToken(c),
		CustomerId:   currentUserId,
		ClientSource: util.GetInterfaceToString(c.Request.Header),
		Url:          GetURL(c),
		Method:       GetMethod(c),
		Request:      GetParams(c),
		Response:     response,
		DealTimes:    util.MilSecond(time.Now()) - GetStartTime(c)/1e6,
	}
	es.InsertEsLog(log)
}

func getAllHeader(c *gin.Context) map[string][]string {
	return c.Request.Header
}

func checkLogType(c *gin.Context) bool {
	_, ok := GetCurrentUserId(c)
	if conf.Es.LogType == 1 && ok {
		return true
	} else if conf.Es.LogType == 2 && !ok {
		return true
	} else if conf.Es.LogType == 3 {
		return true
	}
	return false
}

func checkLog(uri string) bool {
	for _, v := range conf.Es.UnLogUrls {
		if strings.Index(uri, v) == 0 {
			return false
		}
	}
	return true
}
